package com.yjt.common.security;

import java.io.FileInputStream;
import java.io.InputStream;
import java.security.KeyFactory;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Date;
import java.util.Enumeration;

import org.apache.commons.codec.binary.Base64;

/**
 * RSA证书管理工具类
 * 
 * @author hqy 2013-8-22
 * @version 01.00
 * 
 */
public class KeyStoreUtil {
	private final static String DEFAUL_STRING_ENCODING = "utf-8";

	private KeyStoreUtil() {
	}

	/**
	 * 从私钥字符串中获取私钥
	 * 
	 * @param privateKey
	 *            以Base64格式编码的私钥字符串
	 * @return 私钥
	 * @throws Exception
	 */
	public static PrivateKey getPrivateKey(String privateKey) throws Exception {
		byte[] keyBytes = privateKey.getBytes(DEFAUL_STRING_ENCODING);
		byte[] decodeBytes = Base64.decodeBase64(keyBytes);

		PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(decodeBytes);
		KeyFactory keyFactory = KeyFactory.getInstance("RSA");
		PrivateKey key = keyFactory.generatePrivate(keySpec);

		return key;
	}

	/**
	 * 从私钥证书文件中获取私钥
	 * 
	 * @param privateKeyPath
	 *            私钥证书文件路径
	 * @param password
	 *            私钥证书密码
	 * @return 私钥
	 * @throws Exception
	 */
	public static PrivateKey getPrivateKey(String privateKeyPath,
			String password) throws Exception {
		char[] passwordChar = password.toCharArray();
		// 获取私钥
		PrivateKey privateKey = getPrivateKey(privateKeyPath, passwordChar);

		return privateKey;
	}

	/**
	 * 从私钥证书文件中获取私钥
	 * 
	 * @param privateKeyPath
	 *            私钥证书文件路径
	 * @param password
	 *            私钥证书密码
	 * @return 私钥
	 * @throws Exception
	 */
	public static PrivateKey getPrivateKey(String privateKeyPath,
			char[] password) throws Exception {
		// 创建私钥证书输入文件流
		FileInputStream privateKeyFile = new FileInputStream(privateKeyPath);
		// 获取私钥
		PrivateKey privateKey = getPrivateKey(privateKeyFile, password);
		// 关闭输入文件流
		privateKeyFile.close();

		return privateKey;
	}

	/**
	 * 从私钥证书输入流中获取私钥
	 * 
	 * @param privateKeyStream
	 *            私钥证书输入流
	 * @param password
	 *            私钥证书密码
	 * @return 私钥
	 * @throws Exception
	 */
	public static PrivateKey getPrivateKey(InputStream privateKeyStream,
			char[] password) throws Exception {
		/**
		 * 可选的keystore类型：
		 * <p>
		 * (1)jceks:The proprietary keystore implementation provided by the
		 * "SunJCE" provider.
		 * </p>
		 * <p>
		 * (2)jks:The proprietary keystore implementation provided by the "SUN"
		 * provider.
		 * </p>
		 * <p>
		 * (3)pkcs12:The transfer syntax for personal identity information as
		 * defined in PKCS12.
		 * </p>
		 */
		// 获取pkcs12类型的keystore实现
		KeyStore keyStore = KeyStore.getInstance("pkcs12");
		// 加载私钥证书
		keyStore.load(privateKeyStream, password);

		String privateKeyAlias = null;// 私钥别名
		Enumeration<String> aliases = keyStore.aliases();
		if (aliases.hasMoreElements()) {
			// KeyStore中第一个(唯一一个)alias为私钥证书别名
			privateKeyAlias = aliases.nextElement();
		}
		// 获取私钥
		PrivateKey privateKey = (PrivateKey) keyStore.getKey(privateKeyAlias,
				password);

		return privateKey;
	}

	/**
	 * 从公钥字符串中获取公钥
	 * 
	 * @param publicKey
	 *            以Base64格式编码的公钥字符串
	 * @return 公钥
	 * @throws Exception
	 */
	public static PublicKey getPublicKeyFromEncode(String publicKey)
			throws Exception {
		byte[] keyBytes = publicKey.getBytes(DEFAUL_STRING_ENCODING);
		byte[] decodeBytes = Base64.decodeBase64(keyBytes);

		X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decodeBytes);
		KeyFactory keyFactory = KeyFactory.getInstance("RSA");
		PublicKey key = keyFactory.generatePublic(keySpec);

		return key;
	}

	/**
	 * 从公钥证书文件中获取公钥，证书必须是DER编码的
	 * 
	 * @param publicKeyPath
	 *            公钥证书文件路径
	 * @return 公钥
	 * @throws Exception
	 */
	public static PublicKey getPublicKeyFromFile(String publicKeyPath)
			throws Exception {
		// 创建公钥证书输入文件流
		FileInputStream publicKeyFile = new FileInputStream(publicKeyPath);
		// 获取公钥
		PublicKey publicKey = getPublicKey(publicKeyFile);
		// 关闭输入文件流
		publicKeyFile.close();

		return publicKey;
	}

	/**
	 * 从公钥证书输入流中获取公钥，证书必须是DER编码的
	 * 
	 * @param publicKeyStream
	 *            公钥证书输入流
	 * @return 公钥
	 * @throws Exception
	 */
	public static PublicKey getPublicKey(InputStream publicKeyStream)
			throws Exception {
		// 获取实现指定证书类型(X.509)的 CertificateFactory对象
		CertificateFactory cf = CertificateFactory.getInstance("X.509");
		// 生成一个证书对象，并使用从输入流 publicKeyStream 中读取的数据对它进行初始化
		X509Certificate cert = (X509Certificate) cf
				.generateCertificate(publicKeyStream);
		// 获取公钥
		PublicKey publicKey = cert.getPublicKey();

		return publicKey;
	}

	/**
	 * 从公钥证书文件中获取公钥信息，证书必须是DER编码的
	 * 
	 * @param publicKeyPath
	 *            公钥证书文件路径
	 * @return 公钥信息
	 * @throws Exception
	 */
	public static CertificateMessage getCertificate(String publicKeyPath)
			throws Exception {
		// 创建公钥证书输入文件流
		FileInputStream publicKeyFile = new FileInputStream(publicKeyPath);
		// 获取公钥信息
		CertificateMessage certificateMessage = getCertificate(publicKeyFile);
		// 关闭输入文件流
		publicKeyFile.close();

		return certificateMessage;
	}

	/**
	 * 从公钥证书输入流中获取公钥信息，证书必须是DER编码的
	 * 
	 * @param publicKeyStream
	 *            公钥证书输入流
	 * @return 公钥信息
	 * @throws Exception
	 */
	public static CertificateMessage getCertificate(InputStream publicKeyStream)
			throws Exception {
		// 获取实现指定证书类型(X.509)的 CertificateFactory对象
		CertificateFactory cf = CertificateFactory.getInstance("X.509");
		// 生成一个证书对象，并使用从输入流 publicKeyStream 中读取的数据对它进行初始化
		X509Certificate cert = (X509Certificate) cf
				.generateCertificate(publicKeyStream);
		// 获取公钥
		PublicKey publicKey = cert.getPublicKey();

		String dnName = cert.getSubjectDN().getName();// 证书DN
		Date notBefore = cert.getNotBefore();// 证书开始日期
		Date notAfter = cert.getNotAfter();// 证书结束日期

		// 以Base64格式对公钥信息编码
		byte[] publicKeyBytes = publicKey.getEncoded();
		byte[] encodePublicKeyBytes = Base64.encodeBase64(publicKeyBytes);
		String encodePublicKey = new String(encodePublicKeyBytes,
				DEFAUL_STRING_ENCODING);

		// 构造证书公钥信息
		CertificateMessage certificateMessage = new KeyStoreUtil.CertificateMessage(
				publicKey, encodePublicKey, dnName, notBefore, notAfter);

		return certificateMessage;
	}

	/**
	 * 证书公钥信息
	 */
	static class CertificateMessage {
		private PublicKey publicKey;// 证书公钥
		private String publicKeyEncode;// 以Base64格式编码的证书公钥字符串
		private String dnName;// 证书颁发者的可识别名：DN
		private Date notBefore;// 证书开始日期
		private Date notAfter;// 证书结束日期

		public CertificateMessage() {
			super();
		}

		public CertificateMessage(PublicKey publicKey, String publicKeyEncode,
				String dnName, Date notBefore, Date notAfter) {
			super();
			this.publicKey = publicKey;
			this.publicKeyEncode = publicKeyEncode;
			this.dnName = dnName;
			this.notBefore = notBefore;
			this.notAfter = notAfter;
		}

		public PublicKey getPublicKey() {
			return publicKey;
		}

		public void setPublicKey(PublicKey publicKey) {
			this.publicKey = publicKey;
		}

		public String getPublicKeyEncode() {
			return publicKeyEncode;
		}

		public void setPublicKeyEncode(String publicKeyEncode) {
			this.publicKeyEncode = publicKeyEncode;
		}

		public String getDnName() {
			return dnName;
		}

		public void setDnName(String dnName) {
			this.dnName = dnName;
		}

		public Date getNotBefore() {
			return notBefore;
		}

		public void setNotBefore(Date notBefore) {
			this.notBefore = notBefore;
		}

		public Date getNotAfter() {
			return notAfter;
		}

		public void setNotAfter(Date notAfter) {
			this.notAfter = notAfter;
		}
	}
}
